package com.vhans.db.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vhans.core.domain.BUser;
import com.vhans.core.domain.CGroup;
import com.vhans.core.domain.CGroupMsg;
import com.vhans.core.domain.CGroupUser;
import com.vhans.core.utils.BeanCopyUtils;
import com.vhans.core.utils.StringUtils;
import com.vhans.core.web.model.vo.UserIntro;
import com.vhans.db.mapper.BUserMapper;
import com.vhans.db.mapper.CGroupMapper;
import com.vhans.db.mapper.CGroupMsgMapper;
import com.vhans.db.mapper.CGroupUserMapper;
import com.vhans.db.model.dto.ConditionDTO;
import com.vhans.db.model.dto.group.GroupDTO;
import com.vhans.db.model.dto.request.RequestDTO;
import com.vhans.db.model.vo.group.GroupInfoVO;
import com.vhans.db.model.vo.group.GroupVO;
import com.vhans.db.model.vo.group.SearchGroupVo;
import com.vhans.db.service.ICGroupService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 群组Service业务层处理
 *
 * @author vhans
 * @date 2023-05-21
 */
@Service("cGroupServiceImpl")
public class CGroupServiceImpl implements ICGroupService {

    @Autowired
    private CGroupMapper groupMapper;

    @Autowired
    private CGroupUserMapper groupUserMapper;

    @Autowired
    private BUserMapper userMapper;

    @Autowired
    private CGroupMsgMapper groupMsgMapper;


    @Override
    public List<GroupVO> selectCGroupVOList(ConditionDTO condition) {
        // 查询群组信息
        return groupMapper.selectGroupVOList(condition);
    }

    @Override
    public int updateCGroup(GroupDTO group) {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        // 查询群主id
        Integer masterId = groupMapper.selectOne(new LambdaQueryWrapper<CGroup>()
                .select(CGroup::getMasterId)
                .eq(CGroup::getId, group.getId())).getMasterId();
        Assert.isTrue(masterId.equals(userId), "非法人员,禁止操作");
        // 要修改的群组
        CGroup newCGroup = BeanCopyUtils.copyBean(group, CGroup.class);
        return groupMapper.updateById(newCGroup);
    }

    @Override
    public List<SearchGroupVo> searchGroup(GroupDTO groupDTO) {
        // 当前用户id
        int userId = StpUtil.getLoginIdAsInt();
        // 搜索群信息,排除群主自己的群
        return groupMapper.selectList(new LambdaQueryWrapper<CGroup>()
                .select(CGroup::getId, CGroup::getImg, CGroup::getName, CGroup::getRemark, CGroup::getUserNumber)
                .ne(CGroup::getMasterId, userId)
                .eq(CGroup::getName, groupDTO.getName())
                .or()
                .ne(CGroup::getMasterId, userId)
                .eq(CGroup::getGroupNumber, groupDTO.getGroupNumber())
                .orderByDesc(CGroup::getId)).stream().map(item ->
                SearchGroupVo.builder()
                        .id(item.getId())
                        .img(item.getImg())
                        .name(item.getName())
                        .remark(item.getRemark())
                        .userNumber(item.getUserNumber()).build()).toList();
    }

    @Override
    public int createGroup(GroupDTO cGroup) {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        // 要添加的群组
        CGroup newCGroup = BeanCopyUtils.copyBean(cGroup, CGroup.class);
        // 根据时间戳和用户id生成群号
        String groupNumber = Long.toString(System.currentTimeMillis()) + userId;
        newCGroup.setGroupNumber(groupNumber);
        newCGroup.setMasterId(userId);
        return groupMapper.insert(newCGroup);
    }

    @Transactional
    @Override
    public void quitGroup(GroupDTO groupDTO) {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        // 1、先删除与当前用户发送的所有群信息
        delGroupMessagesByGroupIdAndSenderId(groupDTO.getId(), userId);
        // 2、再删除在该群的当前用户
        delGroupUserByGroupIdAndUserId(groupDTO.getId(), userId);
        // 3、群成员个数减1
        decrGroupUserNum(groupDTO.getId(), -1);
    }

    @Transactional
    @Override
    public void deleteGroup(GroupDTO groupDTO) {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        // 查询群主id
        Integer masterId = groupMapper.selectOne(new LambdaQueryWrapper<CGroup>()
                .select(CGroup::getMasterId)
                .eq(CGroup::getId, groupDTO.getId())).getMasterId();
        Assert.isTrue(masterId.equals(userId), "非法人员,禁止操作");
        // 1、先删除该群中所有信息
        delGroupAllMessagesByGroupId(groupDTO.getId());
        // 2、再删除该群的所有成员
        delGroupAllUsersByGroupId(groupDTO.getId());
        // 3、最后删除群账号
        groupMapper.deleteById(groupDTO.getId());
    }

    @Override
    public List<GroupVO> selectJoinGroupList() {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        return groupMapper.getGroupListByUserId(userId);
    }

    @Override
    public List<GroupVO> selectMyGroupList() {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        List<CGroup> cGroups = groupMapper.selectList(new LambdaQueryWrapper<CGroup>()
                .select(CGroup::getId, CGroup::getImg, CGroup::getGroupNumber, CGroup::getName, CGroup::getCreateTime, CGroup::getUserNumber)
                .eq(CGroup::getMasterId, userId));
        return BeanCopyUtils.copyBeanList(cGroups, GroupVO.class);
    }

    @Override
    public GroupInfoVO selectGroupInfoById(Integer id) {
        // 查询群组信息
        GroupInfoVO groupInfoVO = groupMapper.selectGroupInfoById(id);
        Assert.notNull(groupInfoVO, "没有该群组");
        return postUserIntro(groupInfoVO);
    }

    @Override
    public GroupInfoVO selectCGroupInfoByGroupNumber(String groupNumber) {
        // 查询群组信息
        GroupInfoVO groupInfoVO = groupMapper.selectGroupInfoByNumber(groupNumber);
        Assert.notNull(groupInfoVO, "没有该群组");
        return postUserIntro(groupInfoVO);
    }

    @Override
    public List<GroupInfoVO> selectCGroupInfoByUserId(Integer userId) {
        // 查询群基本信息
        List<GroupInfoVO> groupInfoVOList = groupMapper.selectGroupInfoByUserId(userId);
        if (StringUtils.isNotEmpty(groupInfoVOList)) {
            // 封装群信息
            groupInfoVOList.forEach(this::postUserIntro);
            return groupInfoVOList;
        }
        return null;
    }

    @Override
    @Transactional
    public void addNewGroupUser(RequestDTO requestDTO) {
        // 默认用户在群中的名称为昵称
        String nickname = userMapper.selectById(requestDTO.getFromUid()).getNickname();
        // 增加群用户
        groupUserMapper.insert(CGroupUser.builder()
                .groupId(requestDTO.getGroupId())
                .userId(requestDTO.getFromUid())
                .username(nickname).build());
        // 群人数加1
        decrGroupUserNum(requestDTO.getGroupId(), 1);
        //添加一条群消息
        groupMsgMapper.insert(CGroupMsg.builder()
                .groupId(requestDTO.getGroupId())
                .msgType(1)
                .userId(requestDTO.getFromUid())
                .content(nickname + "加入群,热烈欢迎").build());
    }

    @Override
    public List<GroupVO> getRecentGroup(GroupDTO groupDTO) {
        // 用户id
        int userId = StpUtil.getLoginIdAsInt();
        return groupMapper.getRecentGroup(groupDTO, userId);
    }

    /**
     * 扩展群聊信息
     *
     * @param groupInfoVO 要扩展的群聊信息
     * @return 扩展的群聊信息
     */
    @NotNull
    private GroupInfoVO postUserIntro(GroupInfoVO groupInfoVO) {
        List<BUser> userList = groupUserMapper.selectList(new LambdaQueryWrapper<CGroupUser>()
                .select(CGroupUser::getUserId)
                .eq(CGroupUser::getGroupId, groupInfoVO.getId())).stream().map(
                item -> userMapper.selectById(item.getUserId())).toList();
        groupInfoVO.setUserList(userList.stream().map(
                item -> UserIntro.builder()
                        .id(item.getId())
                        .avatar(item.getAvatar())
                        .nickname(item.getNickname())
                        .intro(item.getIntro()).build()).toList());
        return groupInfoVO;
    }

    /**
     * 删除用户发送的群信息
     *
     * @param groupId 群id
     * @param userId  用户id
     */
    private void delGroupMessagesByGroupIdAndSenderId(Integer groupId, Integer userId) {
        groupMsgMapper.delete(new LambdaQueryWrapper<CGroupMsg>()
                .eq(CGroupMsg::getGroupId, groupId)
                .eq(CGroupMsg::getUserId, userId));
    }

    /**
     * 删除群用户
     *
     * @param groupId 群id
     * @param userId  用户id
     */
    private void delGroupUserByGroupIdAndUserId(Integer groupId, Integer userId) {
        groupUserMapper.delete(new LambdaQueryWrapper<CGroupUser>()
                .eq(CGroupUser::getGroupId, groupId)
                .eq(CGroupUser::getUserId, userId));
    }

    /**
     * 改变群人数
     *
     * @param groupId 群id
     * @param num     人数增量
     */
    private void decrGroupUserNum(Integer groupId, Integer num) {
        Integer oldNum = groupMapper.selectGroupUserNumber(groupId);
        groupMapper.updateById(CGroup.builder().id(groupId).userNumber(oldNum + num).build());
    }

    /**
     * 删除群的所有信息
     *
     * @param groupId 群id
     */
    private void delGroupAllMessagesByGroupId(Integer groupId) {
        groupMsgMapper.delete(new LambdaQueryWrapper<CGroupMsg>()
                .eq(CGroupMsg::getGroupId, groupId));
    }

    /**
     * 删除所有群用户
     *
     * @param groupId 群id
     */
    private void delGroupAllUsersByGroupId(Integer groupId) {
        groupUserMapper.delete(new LambdaQueryWrapper<CGroupUser>()
                .eq(CGroupUser::getGroupId, groupId));
    }
}
